package com.flow.asyncflow.core.entity.core;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.flow.asyncflow.core.entity.config.AsyncFlowInfo;
import com.flow.asyncflow.core.entity.log.asyncflowlog.AsyncFlowNodeDetailLogEntity;
import com.flow.asyncflow.core.entity.log.asyncflowlog.AsyncFlowNodeLogEntity;
import com.flow.asyncflow.core.entity.log.businesslog.AsyncFlowBusinessLogEntity;
import com.flow.asyncflow.core.entity.sql.ExecuteSql;
import com.flow.asyncflow.core.node.IFlowNode;
import com.flow.asyncflow.core.utils.beanutils.AsyncFlowBeanUtils;
import com.flow.asyncflow.core.utils.msg.AsyncFlowSendMsg;
import lombok.AccessLevel;
import lombok.Data;
import lombok.Getter;
import lombok.Setter;

import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArrayList;

/**
 * 异步流上下文（工作台）
 */

@Data
public abstract class AsyncFlowBaseContext {

    /**
     * 节点日志
     */
    @Setter(AccessLevel.PRIVATE)
    private List<AsyncFlowNodeLogEntity> asyncFlowNodeLogEntityList = Collections.synchronizedList(new ArrayList<>());
    /**
     * 节点明细日志【AsyncFlowCommon_Log.AddAsyncFlowDetailLog()放在此集合中】
     */
    @Setter(AccessLevel.PRIVATE)
    private ConcurrentHashMap<String, List<AsyncFlowNodeDetailLogEntity>> asyncFlowNodeDetailLogEntityListMap = new ConcurrentHashMap<>();
    /**
     * 业务日志【AsyncFlowBusinessLog.addBusinessLog()放在此集合中】
     */
    @Setter(AccessLevel.PRIVATE)
    private List<AsyncFlowBusinessLogEntity> asyncBusinessLogEntityList = Collections.synchronizedList(new ArrayList<>());
    /**
     * 需要执行的sql【AsyncFlowBuildSql类中的各个方法生成的SQL语句放在此集合中】
     */
    @Setter(AccessLevel.PRIVATE)
    private List<ExecuteSql> executeSQLs =  Collections.synchronizedList(new ArrayList<>());

    @Setter(AccessLevel.PRIVATE)
    private List<DataMapInfo> dataMapInfoList =  Collections.synchronizedList(new ArrayList<>());



    /**
     * 异步流数据仓库
     */
    @Setter(AccessLevel.PRIVATE)
    private ConcurrentHashMap<String, Object> dataSourceMap = new ConcurrentHashMap<>();

    private  Enum<?> operatorEnum;
    /**
     * 节点流信息
     */
    private AsyncFlowInfo asyncFlowInfo = null;
    /**
     * 忽略本次请求的异步流日志
     */
    private boolean ignoreThisReqFlowLog = false;

//    private Class<?> thisMangerClass;
    /**
     * 设置DB数据源实体到数据槽
     *
     * @param object 具体的对象
     */
    public <T> void setData(T object) {

        if (object == null) {
            return;
        }
        Class<?> clazz = object.getClass();
        //不直接用getSimpleName() 是为了优化耗时，这边使用会使得耗时降低5倍左右
        String key = clazz.getName();

        if (key.equals("java.util.ArrayList")) {
            ArrayList<T> objList = ((ArrayList<T>) object);
            if (!objList.isEmpty()) {
                String subKey = objList.get(0).getClass().getName();
                key = subKey + ".List";
            } else {
                //空集合不存入上下文中
                return;
            }
        }
        this.dataSourceMap.put(key, object);
    }

    public <T> void setData(T object, IFlowNode flowNode) {

        if (object == null) {
            return;
        }
        Class<?> clazz = object.getClass();
        //不直接用getSimpleName() 是为了优化耗时，这边使用会使得耗时降低5倍左右
        String key = clazz.getName();

        if (key.equals("java.util.ArrayList")) {
            ArrayList<T> objList = ((ArrayList<T>) object);
            if (!objList.isEmpty()) {
                String subKey = objList.get(0).getClass().getName();
                key = subKey + ".List";
            } else {
                //空集合不存入上下文中
                return;
            }
        }
        this.dataSourceMap.put(key, object);
    }

    /**
     * 获取数据库单个实体【根据对象类型】
     *
     * @param tClass 单个数据实体的类型
     * @param <T>    对象类型
     * @return 具体的对象
     */
    public <T> T getData(Class<T> tClass) {
        String key = tClass.getName();
        T t = null;
        try {
            Object obj = this.dataSourceMap.get(key);
//            if (asyncFlowInfo.isTest()) {
//
//                if (tClass.isEnum()) {
//                    t = (T) obj;
//                } else {
//                    t = JSON.toJavaObject((JSON) obj, tClass);
//                }
//                return t;
//            }

            if (obj != null && obj.getClass() == tClass) {
                t = (T) obj;
            } else {
                if (!tClass.isEnum()) {
                    t = tClass.newInstance();
                }
            }

        } catch (Exception e) {
            String exName = "获取" + tClass.getSimpleName() + "异常【AsyncFlowBaseContext.getData()】";
            String s = AsyncFlowSendMsg.buildErrorMsg(getAsyncFlowRequest(AsyncFlowRequest.class), e, exName, asyncFlowInfo);
            AsyncFlowSendMsg.sendQYWXMsg(asyncFlowInfo.getFlowMaintainName(), s, asyncFlowInfo.getNodeArmUrl());
        }

        return t;
    }

    /**
     * 获取数据库中的集合【根据对象类型获取】
     *
     * @param tClass 单个数据实体的类型
     * @param <T>    具体的对象
     * @return 集合
     */
    public <T> List<T> getListData(Class<T> tClass) {
        //T t=null;
        String key = tClass.getName();
        key = key + ".List";
        List<T> t = null;
        try {
            Object obj = this.dataSourceMap.get(key);
            if (asyncFlowInfo.isTest()) {
                t = new ArrayList<>();
                for (Object o : (JSONArray) obj) {
                    t.add(JSON.toJavaObject((JSON) o, tClass));
                }
            } else {
                t = obj == null ? null : (List<T>) obj;
            }

            if (t == null) {
                t = new ArrayList<>();
            }
        } catch (Exception e) {
            String exName = "获取" + tClass.getSimpleName() + "的集合异常【AsyncFlowBaseContext.getListData()】";
            String s = AsyncFlowSendMsg.buildErrorMsg(getAsyncFlowRequest(AsyncFlowRequest.class), e, exName, asyncFlowInfo);
            AsyncFlowSendMsg.sendQYWXMsg(asyncFlowInfo.getFlowMaintainName(), s, asyncFlowInfo.getNodeArmUrl());
        }
        return t;
    }
    public <T> List<T> getListData(Class<T> tClass,IFlowNode flowNode) {
        //T t=null;
        String key = tClass.getName();
        key = key + ".List";
        List<T> t = null;
        try {
            Object obj = this.dataSourceMap.get(key);
            if (asyncFlowInfo.isTest()) {
                t = new ArrayList<>();
                for (Object o : (JSONArray) obj) {
                    t.add(JSON.toJavaObject((JSON) o, tClass));
                }
            } else {
                t = obj == null ? null : (List<T>) obj;
            }

            if (t == null) {
                t = new ArrayList<>();
            }
        } catch (Exception e) {
            String exName = "获取" + tClass.getSimpleName() + "的集合异常【AsyncFlowBaseContext.getListData()】";
            String s = AsyncFlowSendMsg.buildErrorMsg(getAsyncFlowRequest(AsyncFlowRequest.class), e, exName, asyncFlowInfo);
            AsyncFlowSendMsg.sendQYWXMsg(asyncFlowInfo.getFlowMaintainName(), s, asyncFlowInfo.getNodeArmUrl());
        }
        return t;
    }

    public <T> T getManager(Class<T> tClass) {
       return AsyncFlowBeanUtils.getBean(tClass);
    }

    /**
     * 获取当前节点流请求参数
     *
     * @param <T> 请求参数具体类型
     * @return 请求参数
     */
    public <T> T getRequest(Class<T> tClass) {
        return getData(tClass);
    }

    /**
     * 设置当前节点流请求参数
     *
     * @param t   具体请求参数
     * @param <T> 请求参数具体类型
     */
    public <T> void setRequest(T t) {
        setData(t);
    }

    /**
     * 获取当前节点流返回参数
     *
     * @param <T> 返回参数具体类型
     * @return 返回参数
     */
    public <T> T getResponse(Class<T> tClass) {
        return getData(tClass);

    }

    /**
     * 设置当前节点流返回参数
     *
     * @param t   具体的返回参数
     * @param <T> 返回参数具体类型
     */
    public <T> void setResponse(T t) {
        setData(t);
    }

    /**
     * 获取当前节点流数据上下文
     *
     * @param <T> 数据上下文具体类型
     * @return 数据上下文
     */
    public <T> T getContext(Class<T> tClass) {
        return getData(tClass);
    }

    /**
     * 设置当前节点流数据上下文
     *
     * @param t   具体数据上下文
     * @param <T> 数据上下文具体请求参数
     */
    public <T> void setContext(T t) {
        setData(t);
    }

    /**
     * 设置节点操作类型枚举
     *
     * @param t   具体操作类型
     * @param <T> 枚举操作类型
     */
    public <T> void setReqTypeEnum(T t) {
        setData(t);
    }

    /**
     * 获取节点操作类型枚举
     *
     * @param <T> 枚举类型
     * @return 节点操作枚举
     */
    public <T> T getReqTypeEnum(Class<T> tClass) {
        return getData(tClass);
    }

    /**
     * 获取当前节点流请求参数【整个流】
     *
     * @return 请求参数
     */
    public AsyncFlowRequest getAsyncFlowRequest(Class<AsyncFlowRequest> tClass) {
        return getData(tClass);
    }


    /**
     * 设置当前节点流请求参数
     *
     * @param t 具体请求参数
     */
    public void setAsyncFlowRequest(AsyncFlowRequest t) {
        setData(t);
    }

    /**
     * 获取当前节点流返回参数
     *
     * @param <T> 返回参数具体类型
     * @return 返回参数
     */
    public AsyncFlowResponse getAsyncFlowResponse(Class<AsyncFlowResponse> tClass) {
        return getData(tClass);
    }

    /**
     * 设置当前节点流返回参数
     *
     * @param t 具体的返回参数
     */
    public void setAsyncFlowResponse(AsyncFlowResponse t) {
        setData(t);
    }

}
